﻿using System.Collections.ObjectModel;
using System.Diagnostics;
using KinonekoSoftware.Extensions.Collections;
using KinonekoSoftware.ArkSpark.Core.Delegates;
using KinonekoSoftware.ArkSpark.Core.Messages;
using KinonekoSoftware.ArkSpark.Documents;
using KinonekoSoftware.ArkSpark.Runtimes.Presenters;
using KinonekoSoftware.Foundation.UI.Commands;
using MessageHandlerDictionary = System.Collections.Generic.Dictionary<System.Type, KinonekoSoftware.ArkSpark.Core.Delegates.MessageHandler>;

namespace KinonekoSoftware.ArkSpark.Runtimes
{
    public abstract partial class ArkSparkMQ : Spark, IArkSparkMQ
    {
        private readonly MessageHandlerDictionary _Handlers;
        private readonly object                   _Sync;




        protected ArkSparkMQ()
        {
            _Handlers          = new MessageHandlerDictionary();
            _Elements          = new List<DocumentElement>(32);
            _ElementPresenters = new ObservableCollection<DocumentElementPresenter>();
            _VisibleElements   = new ObservableCollection<DocumentElementPresenter>();
            _Sync              = new object();

            _FactoriesByType = new Dictionary<Type, DocumentElementPresenterFactory>();

            RemoveElementCommand   = new FuncCommand<DocumentElementPresenter>(DoRemoveElementCommand);
            NewParagraphCommand    = new ActionCommand(DoNewParagraphCommand);
            NewHeadingText1Command = new ActionCommand(DoNewHeadingText1Command);
            NewHeadingText2Command = new ActionCommand(DoNewHeadingText2Command);
            NewHeadingText3Command = new ActionCommand(DoNewHeadingText3Command);
            NewHeadingText4Command = new ActionCommand(DoNewHeadingText4Command);
            NewHeadingText5Command = new ActionCommand(DoNewHeadingText5Command);
            NewHeadingText6Command = new ActionCommand(DoNewHeadingText6Command);
            NewHeadingText7Command = new ActionCommand(DoNewHeadingText7Command);
            NewPictureCommand      = new ActionCommand(DoNewPictureCommand);

            //
            //
            Initialize();
        }

        //-------------------------------------------------------------
        //
        //          Method:
        //          Initialize
        //
        //-------------------------------------------------------------
        private void Initialize()
        {
            InitializeHandlers();
            InitializeFactories();
        }


        private void InitializeHandlers()
        {
            AddHandler<ElementUpdatedEventArgs>(ElementUpdatedEventHandler);
            AddHandler<ExternalProcessEventArgs>(ExternalProcessEventHandler);
            AddHandler<PictureElementUpdatedEventArgs>(PictureElementUpdatedEventHandler);
            AddHandler<NewSelectionEventArgs>(NewSelectionEventHandler);
            AddHandler<NewVisibleScopedEventArgs>(NewVisibleScopedEventArgsHandler);
        }

        //-------------------------------------------------------------
        //
        //          Handlers
        //
        //  containing Handlers：
        //  [1] ElementUpdatedEventHandler
        //  [2] ExternalProcessEventHandler
        //  [3] PictureElementUpdatedEventHandler
        //
        //-------------------------------------------------------------

        private void ElementUpdatedEventHandler(IArkSparkEvent @event)
        {
            //
            //
            TextChanged?.Invoke();
        }

        private async void ExternalProcessEventHandler(IArkSparkEvent @event)
        {
            if (@event is not ExternalProcessEventArgs args)
            {
                return;
            }


            //
            //
            var task = ExternalProcessing?.Invoke(args.Target);


            if (task is null)
            {
                return;
            }

            //
            //
            await task;
        }

        private void PictureElementUpdatedEventHandler(IArkSparkEvent @event)
        {
            if (@event is not PictureElementUpdatedEventArgs args)
            {
                return;
            }

            //
            //
            args.Task = new Task(() => OnPictureUpdated(args.Target));
        }




        //-------------------------------------------------------------
        //
        //          Helper Methods
        //
        //-------------------------------------------------------------

        /// <summary>
        /// 获取ID
        /// </summary>
        /// <returns>返回一个表示ID字符串实例。</returns>
        /// <example>返回的ID字符串：2e617f9dbee641a19d45ac8270223c5e</example>
        public static string GetID() => Guid.NewGuid().ToString("N");


        //-------------------------------------------------------------
        //
        //     Handler Methods
        //              AddHandler / RemoveHandler / Handlers
        //
        //-------------------------------------------------------------
        #region AddHandler / RemoveHandler / Handlers

        /// <summary>
        /// 添加消息处理器
        /// </summary>
        /// <param name="type">消息类型</param>
        /// <param name="handler">消息处理器</param>
        protected void AddHandler(Type type, MessageHandler handler)
        {
            if (type is null || handler is null)
            {
                return;
            }

            lock (_Sync)
            {
                if (_Handlers.TryAdd(type, handler))
                {
                    Debug.WriteLine($"添加消息处理器 -> {type.Name}");
                }
            }
        }

        /// <summary>
        /// 添加消息处理器
        /// </summary>
        /// <param name="handler">消息处理器</param>
        /// <typeparam name="T">消息类型</typeparam>
        protected void AddHandler<T>(MessageHandler handler) where T : IArkSparkEvent
        {
            if (handler is null)
            {
                return;
            }
            //
            //
            AddHandler(typeof(T), handler);
        }

        /// <summary>
        /// 移除消息处理器
        /// </summary>
        /// <param name="type">消息类型</param>
        protected void RemoveHandler(Type type)
        {
            if (type is null)
            {
                return;
            }

            lock (_Sync)
            {
                if (_Handlers.Remove(type))
                {
                    Debug.WriteLine($"移除消息处理器 -> {type.Name}");
                }
            }
        }

        /// <summary>
        /// 移除消息处理器
        /// </summary>
        /// <typeparam name="T">消息类型</typeparam>
        protected void RemoveHandler<T>() where T : IArkSparkEvent
        {
            //
            //
            RemoveHandler(typeof(T));
        }

        void IArkSparkMQ.OnNext(IArkSparkEvent @event)
        {
            if (@event is null)
            {
                return;
            }

            if (OnEventHandling(@event))
            {
                return;
            }

            lock (_Sync)
            {
                if (_Handlers.TryGetValue(@event.GetType(), out var handler))
                {
                    handler(@event);
                }
                else
                {
                    Debug.WriteLine($"缺少消息处理器 -> {@event.GetType().Name}");
                }
            }

            //
            // 可以被其他事件捕获。
            Handling?.Invoke(@event);
        }


        protected virtual bool OnEventHandling(IArkSparkEvent @event)
        {
            return false;
        }

        public event MessageHandler Handling;

        #endregion


        //-------------------------------------------------------------
        //
        //          Helper Methods
        //
        //-------------------------------------------------------------
        #region Statistic

        protected void Statistic()
        {
            foreach (var spark in Collection)
            {
                if (spark is IArkSparkTextModel iArkSparkTextModel)
                {
                    TotalCharacterCount += iArkSparkTextModel.Content.Length;
                }

                TotalElementCount++;
            }
        }

        #endregion


        //-------------------------------------------------------------
        //
        //          Helper Methods
        //
        //-------------------------------------------------------------
        #region Load / Save

        public void Load(IDocument document)
        {
            if (document is null)
            {
                return;
            }

            //
            // 确保集合存在
            document.Elements ??= new List<DocumentElement>(32);

            //
            // 切割元素
            for (var i = 0; i < document.Elements.Count; i++)
            {
                var x = document.Elements[i];

                if (x is IArkSparkTextModel { IsModified: true } iArkSparkTextModel)
                {
                    //
                    //
                    var contents   = SplitTextModelContent(iArkSparkTextModel.Content);
                    var paragraphs = contents.Select(CreateParagraph).ToList();


                    //
                    //
                    iArkSparkTextModel.IsModified = false;


                    //
                    //
                    document.Elements.AddRange(paragraphs);
                    document.Elements.RemoveAt(i + paragraphs.Count);
                }
            }

            //
            // 添加集合
            Add(document.Elements);
        }

        public void Save()
        {

        }

        #endregion


        //-------------------------------------------------------------
        //
        //         Methods :
        //
        //         Add / Remove / Move / Clear 
        //
        //-------------------------------------------------------------
        #region Add / Remove / Move / Clear

        private void Add(IEnumerable<DocumentElement> elements)
        {
            if (elements is null)
            {
                return;
            }

            foreach (var element in elements)
            {
                //
                //
                var presenter = GetPresenter(element);

                //
                //
                _Elements.Add(element);
                _ElementPresenters.Add(presenter);
            }

            //
            //
            TextChanged?.Invoke();
            ModelChanged?.Invoke();
        }

        public void Add(DocumentElement element)
        {
            if (element is null)
            {
                return;
            }

            Add(GetPresenter(element));
        }

        public void Add(DocumentElement element, int index)
        {
            if (element is null)
            {
                return;
            }

            Add(GetPresenter(element), index);
        }

        public void Add(DocumentElementPresenter element)
        {
            if (element is null)
            {
                return;
            }

            if (_Document is not null)
            {
                //
                // 添加元素到Document当中。
                _Document.Elements.Add(element.GetDocumentElement());
            }

            //
            //
            _Elements.Add(element.GetDocumentElement());
            _ElementPresenters.Add(element);

            Select(element);

            //
            //
            TextChanged?.Invoke();
            ModelChanged?.Invoke();
        }

        public void Add(DocumentElementPresenter element, int index)
        {
            if (element is null)
            {
                return;
            }

            if (index < 0)
            {
                index = 0;
            }

            //
            //
            _Elements.Insert(index, element.GetDocumentElement());
            _ElementPresenters.Insert(index, element);
            Select(element);

            //
            //
            TextChanged?.Invoke();
            ModelChanged?.Invoke();
        }

        public void Clear()
        {
            _Elements.Clear();
            _ElementPresenters.Clear();
            _Document.Elements.Clear();

            ClearSelection(-1);
            TextChanged?.Invoke();
            ModelChanged?.Invoke();
        }

        public void ShiftUp(DocumentElementPresenter presenter) => Move(presenter, true);

        public void ShiftDown(DocumentElementPresenter presenter) => Move(presenter, false);

        public void Move(DocumentElementPresenter presenter, bool up)
        {
            if (presenter is null)
            {
                return;
            }

            var indexAtPresenter = _ElementPresenters.IndexOf(x => x.Id == presenter.Id);

            //
            //
            _ElementPresenters.Move(indexAtPresenter, up ? indexAtPresenter - 1 : indexAtPresenter + 1);

            //
            //
            if (up)
            {
                _Elements.ShiftUp(presenter.GetDocumentElement());
                _Document.Elements.ShiftUp(presenter.GetDocumentElement());
            }
            else
            {
                _Document.Elements.ShiftDown(presenter.GetDocumentElement());
                _Elements.ShiftDown(presenter.GetDocumentElement());
            }

            //
            //
            ModelChanged?.Invoke();
            TextChanged?.Invoke();
        }

        public void Remove(DocumentElementPresenter element)
        {
            if (element is null)
            {
                return;
            }

            var index  = _Elements.IndexOf(x => x.Id          == element.Id);
            var index2 = _ElementPresenters.IndexOf(x => x.Id == element.Id);

            //
            //
            Debug.Assert(index == index2);

            if (index > -1)
            {
                //
                // 清除选择
                if (Selection is not null && Selection.Id == element.Id)
                {
                    ClearSelection(index);
                }

                //
                //
                _Elements.RemoveAt(index);
                _ElementPresenters.RemoveAt(index);


                //
                // 设置已经
                TextChanged?.Invoke();
            }

        }

        #endregion


        public ObservableCollection<DocumentElementPresenter> VisibleElements => _VisibleElements;
        public ObservableCollection<DocumentElementPresenter> Collection      => _ElementPresenters;


        protected abstract void OnPictureUpdated(DocumentElementPresenter<PictureElement> presenter);


        public int TotalCharacterCount { get; private set; }
        public int TotalDigitCount     { get; private set; }
        public int TotalWhiteCount     { get; private set; }
        public int TotalLineCount      { get; private set; }
        public int TotalElementCount   { get; private set; }

        /// <summary>
        /// 内容发生更改的事件
        /// </summary>
        /// <remarks>
        /// 启用限流算法，保证只会每隔100-500ms扫描一次。
        /// </remarks>
        public event Action TextChanged;
        public event Action ModelChanged;

        /// <summary>
        /// 
        /// </summary>
        public MessageHandler ForwardHandler { get; set; }
    }
}